/**
 * PHP 代码分析器
 */
import * as vscode from 'vscode';
import { FunctionInfo, AnalysisResult, ExtensionConfig } from './types';
import { Logger } from './logger';
import { ConfigManager } from './config';

/**
 * PHP 函数分析器类
 */
export class PhpAnalyzer {
    private readonly logger: Logger;

    // 改进的 PHP 函数匹配正则表达式
    private static readonly FUNCTION_REGEX = /(?:(?:public|protected|private|static|abstract|final)\s+)*function\s+([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*\(/g;

    constructor() {
        this.logger = Logger.getInstance();
    }

    /**
     * 分析 PHP 文档中的函数
     */
    public async analyzeDocument(document: vscode.TextDocument, config: ExtensionConfig): Promise<AnalysisResult> {
        const startTime = Date.now();
        this.logger.debug(`开始分析文档: ${document.fileName}`);

        const result: AnalysisResult = {
            functions: [],
            zeroRefRanges: [],
            hasErrors: false,
            errors: []
        };

        try {
            // 提取所有函数
            const functions = this.extractFunctions(document);
            this.logger.debug(`找到 ${functions.length} 个函数`);

            // 过滤排除的函数
            const filteredFunctions = functions.filter(func =>
                !ConfigManager.shouldExcludeFunction(func.name, config.excludePatterns)
            );

            this.logger.debug(`过滤后剩余 ${filteredFunctions.length} 个函数`);

            // 分析引用
            const analysisPromises = filteredFunctions.map(func =>
                this.analyzeFunctionReferences(document, func, config.maxRetries)
            );

            const analysisResults = await Promise.allSettled(analysisPromises);

            // 处理结果
            // 处理结果
            for (let i = 0; i < analysisResults.length; i++) {
                const analysisResult = analysisResults[i];
                const originalFunction = filteredFunctions[i];

                if (!analysisResult || !originalFunction) {
                    continue;
                }

                if (analysisResult.status === 'fulfilled') {
                    const functionInfo = analysisResult.value;
                    result.functions.push(functionInfo);

                    if (functionInfo.isZeroReference) {
                        result.zeroRefRanges.push(functionInfo.range);
                    }
                } else {
                    result.hasErrors = true;
                    const errorMsg = `分析函数 ${originalFunction.name} 失败: ${analysisResult.reason}`;
                    result.errors.push(errorMsg);
                    this.logger.error(errorMsg);
                }
            }
            const duration = Date.now() - startTime;
            this.logger.debug(`分析完成，耗时 ${duration}ms，找到 ${result.zeroRefRanges.length} 个零引用函数`);

        } catch (error) {
            result.hasErrors = true;
            const errorMsg = `文档分析失败: ${error instanceof Error ? error.message : String(error)}`;
            result.errors.push(errorMsg);
            this.logger.error(errorMsg, error instanceof Error ? error : undefined);
        }

        return result;
    }

    /**
     * 提取文档中的所有函数
     */
    private extractFunctions(document: vscode.TextDocument): Array<{ name: string; range: vscode.Range }> {
        const text = document.getText();
        const functions: Array<{ name: string; range: vscode.Range }> = [];
        let match;

        // 重置正则表达式的 lastIndex
        PhpAnalyzer.FUNCTION_REGEX.lastIndex = 0;

        while ((match = PhpAnalyzer.FUNCTION_REGEX.exec(text)) !== null) {
            const functionName = match[1];

            if (!functionName || !match[0]) {
                continue;
            }

            // 计算函数名在文档中的准确位置
            const functionNameIndex = match[0].lastIndexOf(functionName);
            const startPos = document.positionAt(match.index + functionNameIndex);
            const endPos = document.positionAt(match.index + functionNameIndex + functionName.length);
            const range = new vscode.Range(startPos, endPos);

            functions.push({
                name: functionName,
                range: range
            });
        }

        return functions;
    }

    /**
     * 分析单个函数的引用
     */
    private async analyzeFunctionReferences(
        document: vscode.TextDocument,
        func: { name: string; range: vscode.Range },
        maxRetries: number
    ): Promise<FunctionInfo> {
        let retryCount = 0;
        let lastError: Error | undefined;

        while (retryCount <= maxRetries) {
            try {
                const locations = await vscode.commands.executeCommand<vscode.Location[]>(
                    'vscode.executeReferenceProvider',
                    document.uri,
                    func.range.start
                );

                const referenceCount = locations ? locations.length : 0;
                const isZeroReference = referenceCount <= 1; // 只有定义本身

                this.logger.debug(`函数 ${func.name}: 找到 ${referenceCount} 个引用`);

                return {
                    name: func.name,
                    range: func.range,
                    referenceCount,
                    isZeroReference
                };

            } catch (error) {
                lastError = error instanceof Error ? error : new Error(String(error));
                retryCount++;

                if (retryCount <= maxRetries) {
                    const delay = 1000 * retryCount; // 递增延迟
                    this.logger.warn(`函数 ${func.name} 引用查找失败，${delay}ms 后重试 (${retryCount}/${maxRetries})`);
                    await this.delay(delay);
                } else {
                    this.logger.error(`函数 ${func.name} 引用查找最终失败`, lastError);
                }
            }
        }

        // 如果所有重试都失败，返回默认值
        throw lastError ?? new Error(`函数 ${func.name} 引用查找失败`);
    }

    /**
     * 延迟工具方法
     */
    private delay(ms: number): Promise<void> {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    /**
     * 检查文档是否为 PHP 文件
     */
    public static isPhpDocument(document: vscode.TextDocument): boolean {
        return document.languageId === 'php';
    }
}